home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / mac / tclMacInterupt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  6.9 KB  |  290 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclMacInterupt.c --
  3.  *
  4.  *    This file contains routines that deal with the Macintosh's low level
  5.  *    time manager.  This code provides a better resolution timer than what
  6.  *    can be provided by WaitNextEvent.  
  7.  *
  8.  * Copyright (c) 1996 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tclMacInterupt.c 1.16 96/12/12 19:22:01
  14.  */
  15.  
  16. #include "tclInt.h"
  17. #include "tclMacInt.h"
  18. #include <LowMem.h>
  19. #include <Processes.h>
  20. #include <Timer.h>
  21.  
  22. /*
  23.  * Data structure for timer tasks.
  24.  */
  25. typedef struct TMInfo {
  26.     TMTask        tmTask;
  27.     ProcessSerialNumber    psn;
  28.     Point         lastPoint;
  29.     Point         newPoint;
  30.     long         currentA5;
  31.     long         ourA5;
  32.     int            installed;
  33. } TMInfo;
  34.  
  35. /*
  36.  * Globals used within this file.
  37.  */
  38.  
  39. static TimerUPP sleepTimerProc = NULL;
  40. static int interuptsInited = false;
  41. static ProcessSerialNumber applicationPSN;
  42. #define MAX_TIMER_ARRAY_SIZE 16
  43. static TMInfo timerInfoArray[MAX_TIMER_ARRAY_SIZE];
  44. static int topTimerElement = 0;
  45.  
  46. /*
  47.  * Prototypes for procedures that are referenced only in this file:
  48.  */
  49.  
  50. #if !GENERATINGCFM
  51. static TMInfo *     GetTMInfo(void) ONEWORDINLINE(0x2E89); /* MOVE.L A1,(SP) */
  52. #endif
  53. static void        SleepTimerProc _ANSI_ARGS_((void));
  54. static pascal void    CleanUpExitProc _ANSI_ARGS_((void));
  55. static void        InitInteruptSystem _ANSI_ARGS_((void));
  56.  
  57. /*
  58.  *----------------------------------------------------------------------
  59.  *
  60.  * InitInteruptSystem --
  61.  *
  62.  *    Does various initialization for the functions used in this 
  63.  *    file.  Sets up Universial Pricedure Pointers, installs a trap
  64.  *    patch for ExitToShell, etc.
  65.  *
  66.  * Results:
  67.  *    None.
  68.  *
  69.  * Side effects:
  70.  *    Various initialization.
  71.  *
  72.  *----------------------------------------------------------------------
  73.  */
  74.  
  75. void
  76. InitInteruptSystem()
  77. {
  78.     int i;
  79.     
  80.     sleepTimerProc = NewTimerProc(SleepTimerProc);
  81.     GetCurrentProcess(&applicationPSN);
  82.     for (i = 0; i < MAX_TIMER_ARRAY_SIZE; i++) {
  83.     timerInfoArray[i].installed = false;
  84.     }
  85.     
  86.     /*
  87.      * Install the ExitToShell patch.  We use this patch instead
  88.      * of the Tcl exit mechanism because we need to ensure that
  89.      * these routines are cleaned up even if we crash or are forced
  90.      * to quit.  There are some circumstances when the Tcl exit
  91.      * handlers may not fire.
  92.      */
  93.      
  94.     TclMacInstallExitToShellPatch(CleanUpExitProc);
  95.     interuptsInited = true;
  96. }
  97.  
  98. /*
  99.  *----------------------------------------------------------------------
  100.  *
  101.  * TclMacStartTimer --
  102.  *
  103.  *    Install a Time Manager task to wake our process up in the
  104.  *    future.  The process should get a NULL event after ms 
  105.  *    milliseconds.
  106.  *
  107.  * Results:
  108.  *    None.
  109.  *
  110.  * Side effects:
  111.  *    Schedules our process to wake up.
  112.  *
  113.  *----------------------------------------------------------------------
  114.  */
  115.  
  116. void *
  117. TclMacStartTimer(
  118.     long ms)        /* Milliseconds. */
  119. {
  120.     TMInfo *timerInfoPtr;
  121.     
  122.     if (!interuptsInited) {
  123.     InitInteruptSystem();
  124.     }
  125.     
  126.     /*
  127.      * Obtain a pointer for the timer.  We only allocate up
  128.      * to MAX_TIMER_ARRAY_SIZE timers.  If we are past that
  129.      * max we return NULL.
  130.      */
  131.     if (topTimerElement < MAX_TIMER_ARRAY_SIZE) {
  132.     timerInfoPtr = &timerInfoArray[topTimerElement];
  133.     topTimerElement++;
  134.     } else {
  135.     return NULL;
  136.     }
  137.     
  138.     /*
  139.      * Install timer to wake process in ms milliseconds.
  140.      */
  141.     timerInfoPtr->tmTask.tmAddr = sleepTimerProc;
  142.     timerInfoPtr->tmTask.tmWakeUp = 0;
  143.     timerInfoPtr->tmTask.tmReserved = 0;
  144.     timerInfoPtr->psn = applicationPSN;
  145.     timerInfoPtr->installed = true;
  146.  
  147.     InsTime((QElemPtr) timerInfoPtr);
  148.     PrimeTime((QElemPtr) timerInfoPtr, (long) ms);
  149.  
  150.     return (void *) timerInfoPtr;
  151. }
  152.  
  153. /*
  154.  *----------------------------------------------------------------------
  155.  *
  156.  * TclMacRemoveTimer --
  157.  *
  158.  *    Remove the timer event from the Time Manager.
  159.  *
  160.  * Results:
  161.  *    None.
  162.  *
  163.  * Side effects:
  164.  *    A scheduled timer would be removed.
  165.  *
  166.  *----------------------------------------------------------------------
  167.  */
  168.  
  169. void
  170. TclMacRemoveTimer(
  171.     void * timerToken)        /* Token got from start timer. */
  172. {
  173.     TMInfo *timerInfoPtr = (TMInfo *) timerToken;
  174.     
  175.     if (timerInfoPtr == NULL) {
  176.     return;
  177.     }
  178.     
  179.     RmvTime((QElemPtr) timerInfoPtr);
  180.     timerInfoPtr->installed = false;
  181.     topTimerElement--;
  182. }
  183.  
  184. /*
  185.  *----------------------------------------------------------------------
  186.  *
  187.  * TclMacTimerExpired --
  188.  *
  189.  *    Check to see if the installed timer has expired.
  190.  *
  191.  * Results:
  192.  *    True if timer has expired, false otherwise.
  193.  *
  194.  * Side effects:
  195.  *    None.
  196.  *
  197.  *----------------------------------------------------------------------
  198.  */
  199.  
  200. int
  201. TclMacTimerExpired(
  202.     void * timerToken)        /* Our token again. */
  203. {
  204.     TMInfo *timerInfoPtr = (TMInfo *) timerToken;
  205.     
  206.     if ((timerInfoPtr == NULL) || 
  207.     !(timerInfoPtr->tmTask.qType & kTMTaskActive)) {
  208.     return true;
  209.     } else {
  210.     return false;
  211.     }
  212. }
  213.  
  214. /*
  215.  *----------------------------------------------------------------------
  216.  *
  217.  * SleepTimerProc --
  218.  *
  219.  *    Time proc is called by the is a callback routine placed in the 
  220.  *    system by Tcl_Sleep.  The routine is called at interupt time
  221.  *    and threrfor can not move or allocate memory.  This call will
  222.  *    schedule our process to wake up the next time the process gets
  223.  *    around to consider running it.
  224.  *
  225.  * Results:
  226.  *    None.
  227.  *
  228.  * Side effects:
  229.  *    Schedules our process to wake up.
  230.  *
  231.  *----------------------------------------------------------------------
  232.  */
  233.  
  234. static void
  235. SleepTimerProc()
  236. {
  237.     /*
  238.      * In CFM code we can access our code directly.  In 68k code that
  239.      * isn't based on CFM we must do a glorious hack.  The function 
  240.      * GetTMInfo is an inline assembler call that moves the pointer 
  241.      * at A1 to the top of the stack.  The Time Manager keeps the TMTask
  242.      * info record there before calling this call back.  In order for
  243.      * this to work the infoPtr argument must be the *last* item on the
  244.      * stack.  If we "piggyback" our data to the TMTask info record we 
  245.      * can get access to the information we need.  While this is really 
  246.      * ugly - it's the way Apple recomends it be done - go figure...
  247.      */
  248.     
  249. #if GENERATINGCFM
  250.     WakeUpProcess(&applicationPSN);
  251. #else
  252.     TMInfo * infoPtr;
  253.     
  254.     infoPtr = GetTMInfo();
  255.     WakeUpProcess(&infoPtr->psn);
  256. #endif
  257. }
  258.  
  259. /*
  260.  *----------------------------------------------------------------------
  261.  *
  262.  * CleanUpExitProc --
  263.  *
  264.  *    This procedure is invoked as an exit handler when ExitToShell
  265.  *    is called.  It removes the system level timer handler if it 
  266.  *    is installed.  This must be called or the Mac OS will more than 
  267.  *    likely crash.
  268.  *
  269.  * Results:
  270.  *    None.
  271.  *
  272.  * Side effects:
  273.  *    None.
  274.  *
  275.  *----------------------------------------------------------------------
  276.  */
  277.  
  278. static pascal void
  279. CleanUpExitProc()
  280. {
  281.     int i;
  282.     
  283.     for (i = 0; i < MAX_TIMER_ARRAY_SIZE; i++) {
  284.     if (timerInfoArray[i].installed) {
  285.         RmvTime((QElemPtr) &timerInfoArray[i]);
  286.         timerInfoArray[i].installed = false;
  287.     }
  288.     }
  289. }
  290.